﻿#include "SpinBox.h"

#include <QMouseEvent>
#include <QApplication>
#include <QDebug>
#include <QDesktopWidget>

namespace GeneralUI {

	SpinBox::SpinBox(QWidget *parent)
		: QSpinBox(parent)
		, m_lineEdit(this->lineEdit())
		, m_rightButtonPressed(false)
		, m_lastPosX(0.0)
		, m_isMapping(true)
		, m_specialTextAutoHide(false)
	{
		init();
	}

	SpinBox::~SpinBox()
	{

	}

	QLineEdit * SpinBox::getLineEdit()
	{
		return m_lineEdit;
	}

	void SpinBox::setScreenMapping(bool mapping)
	{
		m_isMapping = mapping;
		update();
	}

	bool SpinBox::isScreenMapping()
	{
		return m_isMapping;
	}

	void SpinBox::setSpecialValueText(const QString &text, const bool autoHide)
	{
		m_specialTextAutoHide = autoHide;
		m_specialText = text;
		QSpinBox::setSpecialValueText(text);
	}

	QString SpinBox::specialValueText(bool &autoHide)
	{
		autoHide = m_specialTextAutoHide;
		return m_specialText;
	}

	bool SpinBox::eventFilter(QObject *obj, QEvent *event)
	{
		if (obj == m_lineEdit)
		{
			//qDebug() << event->type();
			QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
			if (!m_isMapping)
			{
				return QSpinBox::eventFilter(obj, event);
			}

			if (mouseEvent->type() == QEvent::MouseMove && m_rightButtonPressed && isEnabled())
			{
				m_lineEdit->setCursor(QCursor(Qt::SizeHorCursor));
				double _x = mouseEvent->screenPos().x();

				//大于 100 认为幅度过大，选择屏蔽
				if (qAbs(m_lastPosX - _x) > 100)
				{
					m_lastPosX = _x;
					return QSpinBox::eventFilter(obj, event);
				}
				double x = _x / m_screenWidth * (this->maximum() - this->minimum()) + this->minimum();
				this->setValue(x);
				m_lastPosX = _x;
				emit editingFinished();
				mouseEvent->ignore();
			}

			if (mouseEvent->type() == QEvent::MouseButtonPress && mouseEvent->button() == Qt::RightButton && isEnabled())
			{
				int x = m_screenWidth * (this->value() - this->minimum()) / (this->maximum() - this->minimum());
				m_rightButtonPressed = true;
				m_lastPoint = mouseEvent->screenPos();

				QCursor::setPos(QPoint(x, QApplication::desktop()->screenGeometry().height() / 2));
				mouseEvent->ignore();
			}

			if (mouseEvent->type() == QEvent::MouseButtonRelease && m_rightButtonPressed && isEnabled())
			{
				m_lineEdit->setCursor(QCursor(Qt::IBeamCursor));
				m_rightButtonPressed = false;
				QCursor::setPos(m_lastPoint.toPoint());
				emit editingFinished();
				mouseEvent->ignore();
			}
		}
		return QSpinBox::eventFilter(obj, event);
	}

	void SpinBox::keyPressEvent(QKeyEvent *event)
	{
		if (event->key() == Qt::Key_Up)
		{
			updateValue(true);
		}
		else if (event->key() == Qt::Key_Down)
		{
			updateValue(false);
		}
		else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
		{
			clearFocus();
		}
		else if (event->key() == Qt::Key_Escape)
		{
			this->setValue(m_lastValue);
		}
		else
		{
			QSpinBox::keyPressEvent(event);
		}
	}

	void SpinBox::focusInEvent(QFocusEvent *event)
	{
		m_lastValue = value();

		Qt::FocusReason reason = event->reason();
		if (reason == Qt::TabFocusReason || reason == Qt::MouseFocusReason)
		{
			if (m_specialTextAutoHide)
			{
				QSpinBox::setSpecialValueText("");
			}
		}
		__super::focusInEvent(event);
	}

	void SpinBox::focusOutEvent(QFocusEvent *event)
	{
		if (m_specialTextAutoHide)
		{
			QSpinBox::setSpecialValueText(m_specialText);
		}

		// 意外导致失焦时清除映射状态
		m_lineEdit->setCursor(QCursor(Qt::IBeamCursor));
		m_rightButtonPressed = false;

		__super::focusOutEvent(event);
	}

	void SpinBox::wheelEvent(QWheelEvent* event)
	{
		__super::wheelEvent(event);

		emit editingFinished();
	}

	void SpinBox::init()
	{
		this->setFocusPolicy(Qt::ClickFocus);
		this->setContextMenuPolicy(Qt::NoContextMenu);
		this->setButtonSymbols(NoButtons);

		//替换原生输入控件，实现上下按钮增减数值
		m_lineEdit->installEventFilter(this);
		m_screenWidth = QApplication::desktop()->screenGeometry().width() - 1;
	}

	void SpinBox::updateValue(bool isAdd)
	{
		int pos = m_lineEdit->cursorPosition();
		int len = m_lineEdit->text().length();

		int number = this->value();
		int count = len - pos;

		if (pos != 0)
		{
			count = count < 0 ? count + 1 : count;

			if (isAdd)
			{
				number += pow(10, count);
			}
			else
			{
				number -= pow(10, count);
			}

			this->setValue(number);
			emit editingFinished();

			int index = pos - 1 + m_lineEdit->text().length() - len;
			index = qMax(index, 0);  // 不能小于0
			m_lineEdit->setSelection(index, 1);
		}
	}

}//namespace GeneralUI